class GameEngineSystem {


    onStart()
    {

    }
    onFrame(advancedTime) {

    }

    onRecieveEvent(eventName: string) {

    }
}


/**
 * 运行时编辑器点击监听系统
 */
class EditorEngineMouseListenerSystem extends GameEngineSystem {

    currentEvent = null;

    constructor() {
        super();
        window.addEventListener('click', (e) => {
            this.currentEvent = e;

        });
    }

    onClick(e) {
        const mouseGlobalX = e.offsetX;
        const mouseGlobalY = e.offsetY;
        const point = { x: mouseGlobalX, y: mouseGlobalY };
        let result = this.hitTest(core.root, point);
        while (result) {
            if (result.onClick) {
                result.onClick();
            }
            result = result.parent;
        }
    }

    hitTest(gameObject, point) {
        if (gameObject.renderer) {
            return gameObject.renderer.hitTest(point);
        }
        else {

            for (let i = gameObject.$children.length - 1; i >= 0; i--) {
                const child = gameObject.$children[i];
                const childTransform = child.getBehaviour(Transform);
                const localMatrix = childTransform.$localMatrix;
                const invertLocalMatrix = invertMatrix(localMatrix);
                //相对于子对象的相对坐标 = 相对于当前对象的相对坐标 * 子对象的相对矩阵的逆矩阵
                const childLocalPoint = pointAppendMatrix(point, invertLocalMatrix);
                const result = this.hitTest(child, childLocalPoint)
                if (result) {
                    return result;
                }
            }
            return null;
        }
    }

    onFrame(advancedTime) {
        if (this.currentEvent) {
            this.onClick(this.currentEvent);
            this.currentEvent = null;
        }
    }
}

/**
 * 运行时鼠标点击监听系统
 */
class GameEngineMouseListenerSystem extends GameEngineSystem {

    currentEvent = null;

    constructor() {
        super();
        window.addEventListener('click', (e) => {
            this.currentEvent = e;
            this.playAudio("bgm");
        });
    }

    onClick(e) {
        const mouseGlobalX = e.offsetX;
        const mouseGlobalY = e.offsetY;
        const point = { x: mouseGlobalX, y: mouseGlobalY };
        let result = this.hitTest(core.root, point);
        while (result) {
            if (result.onClick) {
                result.onClick();
            }
            result = result.parent;
        }
    }
    playAudio(audioId: string) {
        const audio = document.getElementById(audioId);

        if (audio) {
            audio.play();
        }
    }
    hitTest(gameObject, point) {

        if (gameObject.$isActive)
            if (gameObject.renderer) {
                return gameObject.renderer.hitTest(point);
            }
            else {

                for (let i = gameObject.$children.length - 1; i >= 0; i--) {
                    const child = gameObject.$children[i];
                    const childTransform = child.getBehaviour(Transform);
                    const localMatrix = childTransform.$localMatrix;
                    const invertLocalMatrix = invertMatrix(localMatrix);
                    //相对于子对象的相对坐标 = 相对于当前对象的相对坐标 * 子对象的相对矩阵的逆矩阵
                    const childLocalPoint = pointAppendMatrix(point, invertLocalMatrix);
                    const result = this.hitTest(child, childLocalPoint)
                    if (result) {
                        return result;
                    }
                }
                return null;
            }
    }

    onFrame(advancedTime) {
        if (this.currentEvent) {
            this.onClick(this.currentEvent);
            this.currentEvent = null;
        }
    }
}




class GameEngineRenderSystem extends GameEngineSystem {

    onFrame(advancedTime) {
        this.gameEngineDraw(core.root, context)
    }

    gameEngineDraw(gameObject, context) {
        const transform = gameObject.getBehaviour(Transform);
        transform.calculateGlobalProperties();
        context.setTransform(
            transform.$globalMatrix.a,
            transform.$globalMatrix.b,
            transform.$globalMatrix.c,
            transform.$globalMatrix.d,
            transform.$globalMatrix.tx,
            transform.$globalMatrix.ty
        )
        context.globalAlpha = transform.$globalAlpha;


        if (gameObject.visible ) {
            if (gameObject.renderer) {
                gameObject.renderer.onDraw(context);
            }

            if (gameObject.collider && runningInEditorMode()) {
                gameObject.collider.darwCollider(context);
            }
            for (let child of gameObject.$children) {
                this.gameEngineDraw(child, context);
            }
        }
    }
}

class EditorInputListenerSystem extends GameEngineSystem {

    private editingObject: GameObject;
    targetTransform: Transform;
    private isFirst = true;
    

    onStart()
    {
        //this.KeyBoardMoveMap();
    }

    onRecieveEvent(eventName: string) {
        console.log("收到触发事件：", eventName)
        if (eventName == 'DrawSelectedObjectBorder') {
            
            this.editingObject = core.getselectiedObject();
            console.log(this.editingObject.id + ":" + core.$selectedObject);
            this.targetTransform = this.editingObject.getBehaviour(Transform);
            this.isFirst = false;
            this.MoveGameObjcetByMousemove();
            console.log("当前被选中的对象是" + this.editingObject.id+this.editingObject.uuid)
        }
    }

    onFrame(advancedTime) {
        this.drawWorkSpace('grey');
        this.gameEngineDraw(core.root, context);
    }

    gameEngineDraw(gameObject, context) {
        const transform = gameObject.getBehaviour(Transform);
        transform.calculateGlobalProperties();
        context.setTransform(
            transform.$globalMatrix.a,
            transform.$globalMatrix.b,
            transform.$globalMatrix.c,
            transform.$globalMatrix.d,
            transform.$globalMatrix.tx,
            transform.$globalMatrix.ty
        )
        if (this.isFirst == false) {
            this.drawBorder();
        }
    }
    /**
     * 显示编辑器的编辑区
     * @param backgroundcolor 
     */
    drawWorkSpace(backgroundcolor) {
        context.beginPath();
        context.fillStyle = backgroundcolor;
        context.fillRect(0, 0, GameSize.width, GameSize.height);
    }
    drawBorder() {
        context.lineWidth = 4;
        context.beginPath();
        context.strokeStyle = 'yellow';
        context.moveTo(this.targetTransform.x, this.targetTransform.y);
        context.lineTo(this.targetTransform.x + this.targetTransform.width, this.targetTransform.y);
        context.lineTo(this.targetTransform.x + this.targetTransform.width, this.targetTransform.y + this.targetTransform.height);
        context.lineTo(this.targetTransform.x, this.targetTransform.y + this.targetTransform.height);
        context.lineTo(this.targetTransform.x, this.targetTransform.y);
        context.stroke();
        context.closePath();
    }

    KeyBoardMoveMap()
    {   
        const map = this.editingObject;
        const mapposition = map.getBehaviour(Transform);

        window.addEventListener("keydown", (e) => {
            //左
            if (e.keyCode == 38)
             //if(mapposition.x>0)
              mapposition.x += 50;
             //else mapposition.x =0
             //右
             if (e.keyCode == 39)
             //if(mapposition.x< -GameSize.width+800)
              mapposition.x -= 50;
             //else mapposition.x = -GameSize.width +800
             //上
             if (e.keyCode == 38)
             //if(mapposition.y <0)
              mapposition.y += 50;
             //else mapposition.x =0
             //下
             if (e.keyCode == 40)
             //if(mapposition.y > GameSize.height-600)
              mapposition.y -= 50;
             //else mapposition.x =GameSize.height-600
        });

    }
    MoveGameObjcetByMousemove() {

        const canvasPanel = document.getElementById("gamePanel");
        let isMoveOpen = false;
        canvasPanel.addEventListener("mousemove", (e) => {
            if (isMoveOpen) {
                this.targetTransform.x = e.offsetX - this.targetTransform.width / 2;
                this.targetTransform.y = e.offsetY - this.targetTransform.height / 2;
                if (this.targetTransform.x < 0)
                    this.targetTransform.x = 0;
                if (this.targetTransform.y < 0)
                    this.targetTransform.y = 0;
                if (this.targetTransform.x + this.targetTransform.width > 800)
                    this.targetTransform.x = 800 - this.targetTransform.width;
                if (this.targetTransform.y + this.targetTransform.height > 600)
                    this.targetTransform.y = 600 - this.targetTransform.height;
            }
            else return;
        });
        window.addEventListener("keydown", (e) => {
            if (e.keyCode == 77) {
                isMoveOpen = !isMoveOpen;
                if (isMoveOpen == true)
                    console.log(this.editingObject.id + "处于位置编辑状态，再次按下M键可取消");
                else {
                    console.log("已退出位置编辑状态，按下M键可激活");
                    console.log("当前位置x:", this.targetTransform.x, "y：", this.targetTransform.y)
                    this.editingObject = null;
                    return;
                }
            }
        });

    }

}

/**
 * 游戏引擎运行模式生命周期系统
 */
class GameEnginePlayModeLifeCycleSystem extends GameEngineSystem {


    lastIterationTime = 0;

    lastAdvancedTime = 0;

    onFrame(advancedTime: number) {
        const duringTime = advancedTime - this.lastAdvancedTime;
        this.lastAdvancedTime = advancedTime;
        this.lastIterationTime += duringTime;
        const frameTime = 1000 / 60;
        while (this.lastIterationTime >= frameTime) {
            this.lastIterationTime -= frameTime;
            this.gameObjectOnStart(core.root)
            this.gameObjectOnUpdate(core.root, duringTime);
            this.gameObjectOnDestroy(core.root);
        }
    }

    /**
     * 初始化对象的行为
     */
    gameObjectOnStart(gameObject: GameObject) {
        for (const behaviour of gameObject.$behaviours) {
            if (!behaviour.$isExecuteOnStart) {
                behaviour.onStart();
                behaviour.$isExecuteOnStart = true;
            }
            for (let child of gameObject.$children) {
                this.gameObjectOnStart(child)
            }
        }
    }
    /**
     * 更新化对象的行为
     */
    gameObjectOnUpdate(gameObject: GameObject, duringTime: number) {
        for (const behaviour of gameObject.$behaviours) {
            behaviour.onUpdate(duringTime)
        }
        for (let child of gameObject.$children) {
            this.gameObjectOnUpdate(child, duringTime)
        }
    }
    /**
     * 销毁化对象的行为
     */
    gameObjectOnDestroy(gameObject: GameObject) {
        const newBehaviours = [];
        for (const behaviour of gameObject.$behaviours) {
            if (behaviour.$isDestroy) {
                behaviour.onDestroy();
            }
            else {
                newBehaviours.push(behaviour);
            }
        }
        gameObject.$behaviours = newBehaviours;
    }
}

class EditorApiSystem extends GameEngineSystem {

    private isFirst: boolean = true;

    private currentSceneUrl = core.currentScene;


    onFrame() {
        if (this.isFirst) {
            this.isFirst = false;
            nativeMenu.run(this);
            hierachyPanel.run(this);
            insepectorPanel.run(this);
            resourcePanel.run(this);
        }
    }


    onRecieveEvent(eventName: string) {
        if (eventName == 'sceneChanged') {
            const hierarchyData = getHierarchyData(core.root);
            hierachyPanel.update(hierarchyData);
            insepectorPanel.clear();
        }
    }


    executeCommand(name: string, param?: any) {

        console.log('执行命令', name, '参数', param);
        switch (name) {
            case "SelectGameObject":
                const gameObject = GameObject.getGameObject(param);
                const gameObjectData = getInspectorData(gameObject);
                insepectorPanel.update(gameObjectData);
                core.dispatchSystemEvent('DrawSelectedObjectBorder');
                break;
            case "ModifyBehaviourProperty":
                const behaviour = Behaviour.getBehaviour(param.uuid);
                behaviour[param.key] = param.newValue;
                break;
            case "Save":
                const data = core.toData(core.root.$children[0]);
                const content = JSON.stringify(data, null, '\t');
                const fs = require('fs');
                fs.writeFileSync(this.currentSceneUrl, content, 'utf-8')
                break;
            case "ChangeScene":
                this.currentSceneUrl = param;
                core.currentScene =this.currentSceneUrl;
                core.changeScene(this.currentSceneUrl);
                
                break;
            case "AddBehaviourOnGameObject":
                const { uuid, behaviourName } = param;
                const gameObject1 = GameObject.getGameObject(uuid);
                const behaviourClass = core.getBehaviourClass(behaviourName)
                gameObject1.addBehaviour(new behaviourClass());
                insepectorPanel.update(getInspectorData(gameObject1));
                break;
            case "RemoveBehaviourOnGameObject":
                //param的值为uuid和behaviourName
                const rebehaviourClass = core.getBehaviourClass(param.behaviourName)
                const removeObj = core.getselectiedObject();
                removeObj.removeBehaviourInData(new rebehaviourClass());
                insepectorPanel.update(getInspectorData(removeObj));
                }
        }

    }



